iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 11
0
Data Technology

30天python雜談系列 第 11

版本差異雜談之一———print與括號的糾葛

  • 分享至 

  • xImage
  •  

python 版本差異雜談之一

大魔王系列來拉~~~~

曾經有人這樣說過:

Python是一种“v2/v3”双管枪,每次只能用一个管子发射,你永远不知道该用哪个管子发射好。

這在眾多python愛好者的心裡一定心有戚戚焉,從python2升級到python3,不只語言內部做了很多的更動,更讓人糾結的是,python3並沒有向下兼容python2的語法,在python3發表之後,python最引以為傲的各種強大library都需要一些更動來支援python3的語法,而且也讓當時很熟悉python2語法的使用著們要再重新學習python3的語法和內部規則,所以當時引來的許多人的反彈,甚至有人說python3是一門新的語言,那到底python2和python3究竟有哪些的不同?python3究竟「改善」了什麼東西?我就稍微講一下我自己粗淺的理解吧。

差異一:print函數的變動

大家感受最大的應該就是python2的print語句(statement)變成了print函數(function),也就是說print從python3開始就要加括號了,不然會跑出SyntaxError,看起來要print一個東西出來都要多加一個括號好像很麻煩,但是把print從語句變成函數其實增加了很多好處:

(1)顯示help document:
應該很多人知道python有一個內建函數help(),只要在參數放進想要查閱的函數,就能夠顯示這個函數的help document,顯然在python2作為語句的print是無法藉由help來顯示使用說明的:

https://ithelp.ithome.com.tw/upload/images/20171230/20107274T91v7cB7Lv.png

圖一 python2 help(print)

而在python3作為函數的print,我們可以藉由help()查閱print的使用說明:

https://ithelp.ithome.com.tw/upload/images/20171230/20107274Pk1bkl1oJ0.png

圖二 python3 help(print)

上圖顯示了print在python3作為一個函數多了一些語句所沒有的參數可以設定,下面再用一些例子來解釋這些參數的功能,就可以完全體會到print函數的強大。

(2)分隔符號的使用:
若要印出多個對象,在python2中的print語句有一種常見的用法:

In python2 shell:
>>> print 1,'b',['x','y','z']
1 b ['x', 'y', 'z']

最後的輸出會以空白作為分隔符號,但如果我要在印出類似csv檔的格式,想以','作為分個符號,試試看把多個對象轉為串列並用join()做處理:

In python2 shell:
>>> print ','.join([1,'b',['x','y','z']]) # 會發現join()裡的list不接受非字串的elm
TypeError: sequence item 0: expected string, int found 
>>> print ",".join(map(str,[1,'b',['x','y','z']])) # 只好先用map把每一個elm先轉成字串物件在呼叫join function
1,b,['x', 'y', 'z']

總算是解決分隔符號的問題,但再回頭看看這個解法實在是非常的冗長而且複雜,完全違背了python這個語言原本的初衷,雖說也可以自定義一個print函數來藉著參數設定分隔符號,但既然這是常見的基本功能,理應要在內建函數裡實現才對。

於是在python3,把print語句換成了print函數,順便把分隔符號這個功能實現出來了:

In python3 shell:
>>> print(1,'b',['x','y','z'],sep=',') # print函數使用了sep這個具名參數,很乾淨俐落的實現了分隔符號的設定
1,b,['x', 'y', 'z']

(3)結尾符號的使用:
在python2中,也沒有一個內建函數能夠簡潔的實現結尾符號,可能還是必須透過自訂函數來實現,而且還必須克服許多缺點:

In python2 shell:
>>> import sys
>>> def print_with_end(end='\n',*args):
...     for arg in args:
...         print arg,
...     sys.stdout.write(end)
... 
>>> print_with_end('(the END)\n',1,'b',['x', 'y', 'z'])
1 b ['x', 'y', 'z'] (the END)
>>>     

首先,在python2中,上述的解決方法有一個缺陷,就是具名參數必須要在*args參數之前,否則會出現SyntaxError,但同時這也綁住了具名參數的位置,使得第一個參數必須為end參數,所以在上述例子我把結尾字串'(the END)\n'設定在第一個參數的位置。前面講的缺點可以請讀者自行驗證看看,當然一定還有更好的函數定義方法,但再細講就有些偏題了,且力求簡潔python本就不應該再這麼彆扭的事上打轉,來看看python3的實現方式:

In python3 shell:
>>> print(1,'b',['x', 'y', 'z'],end=' (the END)\n')
1 b ['x', 'y', 'z'] (the END)
>>>

立刻解決。

但如果python2的使用者想要使用python3的print函數的話,future module是一個方便的選擇:

In python2 shell:
>>> from __future__ import print_function
>>> print(1,'b',['x', 'y', 'z'],end=' (the END)\n')
1 b ['x', 'y', 'z'] (the END)
>>> 

對了,可能有人會說,在python2裏面print也可以當函數用阿.....沒錯,但只是看起來是這樣,實際上若在python2使用print(),其還是一個print語句,而後面的()讓輸出的格式變成了一個tuple:

In python2 shell:
>>> print(1,'b',['x', 'y', 'z'])
(1, 'b', ['x', 'y', 'z'])
>>> 

上一篇
repr與str雜談———暴風雨前的輕鬆小品技術文
下一篇
版本差異雜談之二———年末偷懶文
系列文
30天python雜談30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言